package com.sh.data.engine.application.service.api;

import cn.hutool.core.convert.Convert;
import com.sh.data.engine.application.model.dto.api.*;
import com.sh.data.engine.application.model.dto.api.DataApiResponse.DataApiParamResponse;
import com.sh.data.engine.application.model.dto.common.DirectoryResponse;
import com.sh.data.engine.application.model.dto.integration.OfflinePreviewApiDataResponse;
import com.sh.data.engine.application.model.dto.normalization.index.IndexCatalogResponse;
import com.sh.data.engine.application.model.request.api.*;
import com.sh.data.engine.common.enumDefinition.DSType;
import com.sh.data.engine.common.exception.BusinessException;
import com.sh.data.engine.common.util.DataApiTypeUtil;
import com.sh.data.engine.common.util.ServletUtils;
import com.sh.data.engine.domain.api.model.domain.DataApiDomain;
import com.sh.data.engine.domain.api.model.domain.DataApiLogDomain;
import com.sh.data.engine.domain.api.model.domain.DataApiRegisterDomain;
import com.sh.data.engine.domain.api.model.domain.rest.DataApiTaskParamDomain;
import com.sh.data.engine.domain.api.model.param.*;
import com.sh.data.engine.domain.api.service.DataApiService;
import com.sh.data.engine.domain.base.model.UserContext;
import com.sh.data.engine.domain.base.model.enums.DirectoryMenuEnum;
import com.sh.data.engine.domain.common.model.domain.DirectoryDomain;
import com.sh.data.engine.domain.common.service.DirectoryService;
import com.sh.data.engine.domain.dataasset.service.TblPropService;
import com.sh.data.engine.domain.integration.datasource.model.domain.DataSourceDomain;
import com.sh.data.engine.domain.integration.datasource.service.DataSourceService;
import com.sh.data.engine.domain.normalization.index.model.domain.IndexBaseDomain;
import com.sh.data.engine.domain.normalization.index.model.domain.IndexCatalogDomain;
import com.sh.data.engine.domain.normalization.index.model.param.IndexListParam;
import com.sh.data.engine.domain.normalization.index.service.IndexMgtService;
import com.sh.data.engine.domain.secret.service.SecretMgtService;
import com.sh.data.engine.domain.shims.db.model.FieldInfoDomain;
import com.sh.data.engine.domain.shims.db.model.PreviewDataDomain;
import com.sh.data.engine.domain.shims.db.model.TableInfoDomain;
import com.sh.data.engine.domain.util.ConvertUtil;
import com.sh.data.engine.repository.dao.integration.datasource.entity.DataSourceEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: mengzheng.mhc
 * @date: 2024/8/15 18:12
 */
@Slf4j
@Service
public class DataApiApplicationService {

    @Autowired
    private DataApiService dataApiService;

    @Autowired
    private DataSourceService dataSourceService;

    @Autowired
    private DirectoryService directoryService;

    @Autowired
    private IndexMgtService indexMgtService;

    @Autowired
    private TblPropService tblPropService;

    @Autowired
    private SecretMgtService secretMgtService;

    public boolean saveGuideApi(DataApiGuideRequest dataApiGuideRequest) {
        DataApiGuideParam dataApiGuideParams =
            ConvertUtil.copyProperties(dataApiGuideRequest, DataApiGuideParam.class);

        DataSourceEntity targetEntity =
            dataSourceService.getById(dataApiGuideRequest.getDatasourceId());
        boolean targetS = true;

        if (Objects.nonNull(targetEntity.getIsSystem()) && targetEntity.getIsSystem().equals(1)) {
            targetS =
                tblPropService.checkSecretLevel(
                    dataApiGuideRequest.getTableName(),
                    ServletUtils.getProjectId(),
                    UserContext.getUserId());
        }
//        if (!targetS) {
//            userBehaviorLogService.addFailedLog(
//                Business.数据服务, Operation.ADD_UPDATE, dataApiGuideRequest.getApiName(),
//                LogResult.FAILED);
//            throw new BusinessException(StatusCode.FAILED, "密级不符合");
//        }
        List<DataApiParamParam> inputParam =
            ConvertUtil.copyProperties(
                dataApiGuideRequest.getInputParamRequest(), DataApiParamParam.class);
        List<DataApiParamParam> outputParam =
            ConvertUtil.copyProperties(
                dataApiGuideRequest.getOutputParamRequest(), DataApiParamParam.class);
        String userId = UserContext.getUserId();
        Long projectId = ServletUtils.getProjectId();
        dataApiGuideParams.setUserId(userId);
        dataApiGuideParams.setProjectId(projectId);
        dataApiGuideParams.setInputParamList(inputParam);
        dataApiGuideParams.setOutputParamList(outputParam);
        return dataApiService.saveApi(dataApiGuideParams);
    }

    public List<IndexCatalogResponse> listCatalog() {
        Long projectId = ServletUtils.getProjectId();
        List<IndexCatalogDomain> indexCatalogDomains = indexMgtService.listCatalog(projectId);
        return ConvertUtil.copyProperties(indexCatalogDomains, IndexCatalogResponse.class);
    }

    public List<DataApiIndexResponse> getDataApiIndexList(Long catalogId) {
        Long projectId = ServletUtils.getProjectId();

        // 获取某个目录下的子目录
        List<Long> catalogIdList = null;
        if (Objects.nonNull(catalogId) && !catalogId.equals(0L)) {
            catalogIdList = indexMgtService.getAllChildIdByPid(catalogId, projectId);
        }
        IndexListParam indexListParam = new IndexListParam();
        indexListParam.setProjectId(projectId);
        indexListParam.setCatalogIdList(catalogIdList);
        List<IndexBaseDomain> indexPublished =
            indexMgtService.getIndexPublished(projectId, catalogIdList);
        return ConvertUtil.copyProperties(indexPublished, DataApiIndexResponse.class);
    }

    public boolean saveIndexApi(DataApiIndexRequest dataApiIndexRequest) {
        DataApiIndexParam dataApiIndexParam =
            ConvertUtil.copyProperties(dataApiIndexRequest, DataApiIndexParam.class);

        List<DataApiParamParam> inputParam =
            ConvertUtil.copyProperties(
                dataApiIndexRequest.getInputParamRequest(), DataApiParamParam.class);
        List<DataApiParamParam> outputParam =
            ConvertUtil.copyProperties(
                dataApiIndexRequest.getOutputParamRequest(), DataApiParamParam.class);
        boolean targetS = true;
        targetS =
            tblPropService.checkSecretLevel(
                dataApiIndexRequest.getTableName(),
                ServletUtils.getProjectId(),
                UserContext.getUserId());

//        if (!targetS) {
//            userBehaviorLogService.addFailedLog(
//                Business.数据服务, Operation.ADD_UPDATE, dataApiIndexRequest.getApiName(),
//                LogResult.FAILED);
//            throw new BusinessException(StatusCode.FAILED, "密级不符合");
//        }
        dataApiIndexParam.setInputParamList(inputParam);
        dataApiIndexParam.setOutputParamList(outputParam);
        String userId = UserContext.getUserId();
        Long projectId = ServletUtils.getProjectId();
        dataApiIndexParam.setUserId(userId);
        dataApiIndexParam.setProjectId(projectId);
        return dataApiService.saveApi(dataApiIndexParam);
    }

    public boolean saveScriptApi(DataApiScriptRequest dataApiScriptRequest) {
        DataApiScriptParam dataApiScriptParam =
            ConvertUtil.copyProperties(dataApiScriptRequest, DataApiScriptParam.class);

        List<DataApiParamParam> inputParam =
            ConvertUtil.copyProperties(
                dataApiScriptRequest.getInputParamRequest(), DataApiParamParam.class);
        List<DataApiParamParam> outputParam =
            ConvertUtil.copyProperties(
                dataApiScriptRequest.getOutputParamRequest(), DataApiParamParam.class);

        String apiScript = dataApiScriptRequest.getApiScript();

        DataSourceEntity targetEntity =
            dataSourceService.getById(dataApiScriptRequest.getDatasourceId());

        if (Objects.nonNull(targetEntity.getIsSystem()) && targetEntity.getIsSystem().equals(1)) {
            String table = null;
            try {
                table =
                    secretMgtService.validSecretSQL(
                        apiScript, UserContext.getUserId(), ServletUtils.getProjectId());
            } catch (Exception e) {
                // 不做处理
            }
        }
        dataApiScriptParam.setApiScript(apiScript);
        dataApiScriptParam.setInputParamList(inputParam);
        dataApiScriptParam.setOutputParamList(outputParam);
        String userId = UserContext.getUserId();
        Long projectId = ServletUtils.getProjectId();
        dataApiScriptParam.setUserId(userId);
        dataApiScriptParam.setProjectId(projectId);
        dataApiScriptParam.setApiScript(apiScript);
        return dataApiService.saveApi(dataApiScriptParam);
    }

    public List<DataApiParamResponse> getParams(String sql, Long dsId) {
        List<DataApiTaskParamDomain> dataApiTaskParamDomain = dataApiService.getParams(sql, dsId);
        return ConvertUtil.copyProperties(dataApiTaskParamDomain, DataApiParamResponse.class);
    }

    public boolean saveRegisterApi(DataApiRegisterRequest dataApiRegisterRequest) {
        DataApiRegisterParam convert =
            Convert.convert(DataApiRegisterParam.class, dataApiRegisterRequest);

        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();
        convert.setProjectId(projectId);
        convert.setUserId(userId);
        return dataApiService.saveRegisterApi(convert);
    }

    public List<DirectoryResponse> getDataApiGroupList() {
        Long projectId = ServletUtils.getProjectId();
        List<DirectoryDomain> dirList =
            directoryService.getDirList(projectId, DirectoryMenuEnum.API, null);
        return ConvertUtil.copyProperties(dirList, DirectoryResponse.class);
    }

    public List<DataSourceSimpleResponse> getDataSourceList(Integer apiType) {
        Long projectId = ServletUtils.getProjectId();
        List<DataSourceDomain> allByProject = dataSourceService.getAllByProject(projectId);

        return allByProject.stream()
            .filter(
                e ->
                    apiType == null
                        || !DSType.InfluxDB.toString().equals(e.getDsType())
                        || apiType == 1)
            .filter(
                e ->
                    DSType.isRdbms(e.getDsType())
                        || DSType.IoTDB.toString().equals(e.getDsType())
                        || DSType.InfluxDB.toString().equals(e.getDsType()))
            .map(
                e -> {
                    DataSourceSimpleResponse build =
                        DataSourceSimpleResponse.builder()
                            .dsName(e.getDsName())
                            .id(e.getId())
                            .status(e.getStatus())
                            .build();
                    return build;
                })
            .collect(Collectors.toList());
    }

    public List<TableInfoDomain> getTableInfoList(Long id) {
        return dataSourceService.getTableAndViewList(id);
    }

    public OfflinePreviewApiDataResponse previewData(Long dsId, String tableName) {
        PreviewDataDomain previewDataDomain = dataSourceService.previewData(dsId, tableName);

        List<FieldInfoDomain> fieldList = dataSourceService.getFieldList(dsId, tableName);

        List<OfflinePreviewApiDataResponse.FieldInfo> r2 =
            fieldList.stream()
                .map(
                    e -> {
                        OfflinePreviewApiDataResponse.FieldInfo fieldInfo = new OfflinePreviewApiDataResponse.FieldInfo();
                        fieldInfo.setFieldName(e.getFieldName());
                        fieldInfo.setFieldType(e.getFieldType());
                        return fieldInfo;
                    })
                .collect(Collectors.toList());
        OfflinePreviewApiDataResponse response =
            Convert.convert(OfflinePreviewApiDataResponse.class, previewDataDomain);
        response.setFieldNameList(r2);
        return response;
    }

    public List<DataApiSaveFieldResponse> getTableFieldList(Long dsId, String tableName) {
        List<FieldInfoDomain> fieldList = dataSourceService.getFieldList(dsId, tableName);
        List<DataApiSaveFieldResponse> dataApiSaveFieldResponses =
            ConvertUtil.copyProperties(fieldList, DataApiSaveFieldResponse.class);

        dataApiSaveFieldResponses.forEach(
            e -> {
                e.setParamDataType(
                    DataApiTypeUtil.toDataApiType(e.getDataType()).toUpperCase(Locale.ROOT));
                e.setParamDesc(e.getComment());
                e.setBindColumnName(e.getFieldName());
                e.setFieldType(e.getFieldType().toUpperCase(Locale.ROOT));
            });
        return dataApiSaveFieldResponses;
    }

    public DataApiResponse getDataApiDetailById(Long id) {
        DataApiDomain dataApiDomain = dataApiService.getDataApiDetailById(id);
        DataApiRegisterDomain apiRegisterDomain = dataApiDomain.getApiRegisterDomain();
        List<DataApiTaskParamDomain> apiParamDomainList = dataApiDomain.getApiParamEntityList();

        DataApiResponse dataApiResponse =
            ConvertUtil.copyProperties(dataApiDomain, DataApiResponse.class);

        dataApiResponse.setDataApiRegisterDomain(apiRegisterDomain);

        if (apiParamDomainList != null) {
            List<DataApiParamResponse> dataApiParamResponses =
                ConvertUtil.copyProperties(apiParamDomainList, DataApiParamResponse.class);
            Map<Integer, List<DataApiParamResponse>> collect =
                dataApiParamResponses.stream()
                    .collect(Collectors.groupingBy(DataApiParamResponse::getParamType));
            List<DataApiParamResponse> dataApiParamResponses1 = collect.get(0);
            List<DataApiParamResponse> dataApiParamResponses2 = collect.get(1);
            dataApiResponse.setOutputParamResponses(
                dataApiParamResponses2 == null ? new ArrayList<>() : dataApiParamResponses2);
            dataApiResponse.setInputParamResponses(
                dataApiParamResponses1 == null ? new ArrayList<>() : dataApiParamResponses1);
        }
        return dataApiResponse;
    }

    public String getResponseExample(DataApiExampleTestRequest dataApiExampleTestRequest) {
        DataApiExampleTestParam dataApiExampleTestParam =
            ConvertUtil.copyProperties(dataApiExampleTestRequest, DataApiExampleTestParam.class);

        List<DataApiParamParam> dataApiParamParams =
            ConvertUtil.copyProperties(
                dataApiExampleTestRequest.getOutputParamRequest(), DataApiParamParam.class);

        dataApiExampleTestParam.setDataApiParamParams(dataApiParamParams);
        return dataApiService.getResponseExample(dataApiExampleTestParam);
    }

    public Long testGuidApi(DataApiTestRequest dataApiGuideRequest) {
        DataApiTestParam dataApiTestParam =
            ConvertUtil.copyProperties(dataApiGuideRequest, DataApiTestParam.class);

        boolean isIndex = false;
        if (Objects.isNull(dataApiGuideRequest.getDatasourceId())) {
            isIndex = true;
        }

        DataSourceEntity targetEntity =
            dataSourceService.getById(dataApiGuideRequest.getDatasourceId());
        boolean targetS = true;
        String table = null;

        if (isIndex
            || (Objects.nonNull(targetEntity.getIsSystem()) && targetEntity.getIsSystem().equals(1))) {
            if (StringUtils.isNotBlank(dataApiGuideRequest.getApiScript())) {
                try {
                    table =
                        secretMgtService.validSecretSQL(
                            dataApiGuideRequest.getApiScript(),
                            UserContext.getUserId(),
                            ServletUtils.getProjectId());
                } catch (Exception e) {
                    // 不做处理
                }
                if (Objects.nonNull(table)) {
                    throw new BusinessException(String.format("无权限操作脚本中的表,表:%s 密级不符", table));
                }
            } else {
                targetS =
                    tblPropService.checkSecretLevel(
                        dataApiGuideRequest.getTableName(),
                        ServletUtils.getProjectId(),
                        UserContext.getUserId());
            }
        }
        if (Objects.nonNull(table)) {
            throw new BusinessException(
                String.format("无权限操作脚本中的表,表:%s 密级不符", table));
        }
//        if (!targetS) {
//            userBehaviorLogService.addFailedLog(
//                Business.数据服务, Operation.ADD_UPDATE, dataApiGuideRequest.getApiName(),
//                LogResult.FAILED);
//            throw new BusinessException(StatusCode.FAILED, "密级不符合");
//        }
        List<DataApiParamParam> inputParam =
            ConvertUtil.copyProperties(
                dataApiGuideRequest.getInputParamRequest(), DataApiParamParam.class);
        List<DataApiParamParam> outputParam =
            ConvertUtil.copyProperties(
                dataApiGuideRequest.getOutputParamRequest(), DataApiParamParam.class);

        Long projectId = ServletUtils.getProjectId();
        dataApiTestParam.setProjectId(projectId);
        dataApiTestParam.setInputParamList(inputParam);
        dataApiTestParam.setOutputParamList(outputParam);
        return dataApiService.testApi(dataApiTestParam, ServletUtils.getProjectId());
    }

    public Long testRegisterApi(DataApiRegisterRequest dataApiRegisterRequest) {
        DataApiRegisterParam dataApiRegisterParam =
            Convert.convert(DataApiRegisterParam.class, dataApiRegisterRequest);
        Long projectId = ServletUtils.getProjectId();
        String userId = UserContext.getUserId();
        dataApiRegisterParam.setProjectId(projectId);
        dataApiRegisterParam.setUserId(userId);
        return dataApiService.testRegisterApi(dataApiRegisterParam);
    }

    public DataApiLogResponse getRequestLog(Long logId, Integer offset) {
        DataApiLogDomain requestLog = dataApiService.getRequestTestLog(logId, offset);
        return ConvertUtil.copyProperties(requestLog, DataApiLogResponse.class);
    }
}
